﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BitmapTagger;

namespace TagPrinter
{
	/// <summary>
	/// Parsers and stores the application arguments
	/// </summary>
	public class ArgumentParser
	{
		

		/// <summary>
		/// Create a new Argument Parser
		/// </summary>
		/// <param name="args">The application arguments to parse and store</param>
		public ArgumentParser(string[] args)
		{
			SetDefaults();
			Arguments = args;
			Parse();

		}

		/// <summary>
		/// Parse the arguments
		/// </summary>
		private void Parse()
		{
			List<string> argumentList = Arguments.ToList<string>();
			string argument;
			bool conversionWorked;
			bool booleanValue;
			TagPrecedence precedence;
			while (argumentList.Count > 0)
			{
				argument = argumentList[0];
				argumentList.RemoveAt(0);
				if (IsLoadExifOption(argument))
				{
					if (argumentList.Count > 0)
					{
						booleanValue = ConvertTrueFalseStrings(argumentList[0],
							out conversionWorked);
						if (conversionWorked)
						{
							LoadExif = booleanValue;
							argumentList.RemoveAt(0);
						}
						else
							Console.WriteLine("Load Exif option must be followed by t or f");
					}
					else
						Console.WriteLine("Load Exif option must be followed by t or f");
					
				}
				else if (IsLoadXMPExifOption(argument))
				{
					if (argumentList.Count > 0)
					{
						booleanValue = ConvertTrueFalseStrings(argumentList[0],
							out conversionWorked);
						if (conversionWorked)
						{
							LoadXMPExif = booleanValue;
							argumentList.RemoveAt(0);
						}
						else
							Console.WriteLine("Load XMPExif option must be followed by t or f");
					}
					else
						Console.WriteLine("Load XMPExif option must be followed by t or f");
				}
				else if (IsLoadXMPOption(argument))
				{
					if (argumentList.Count > 0)
					{
						booleanValue = ConvertTrueFalseStrings(argumentList[0],
							out conversionWorked);
						if (conversionWorked)
						{
							LoadXMP = booleanValue;
							argumentList.RemoveAt(0);
						}
						else
							Console.WriteLine("Load XMP option must be followed by t or f");
					}
					else
						Console.WriteLine("Load XMP option must be followed by t or f");
				}
				else if (IsPrecedenceOption(argument))
				{
					if (argumentList.Count > 0)
					{
						precedence = ConvertPrecedenceStrings(argumentList[0],
							out conversionWorked);
						if (conversionWorked)
						{
							Precedence = precedence;
							argumentList.RemoveAt(0);
						}
						else
							Console.WriteLine("Tag Precedence option must be followed by a valid value, to see a listing of valid values use the help option . -h");
					}
					else
						Console.WriteLine("Tag Precedence option must be followed by a valid value, to see a listing of valid values use the help option . -h");
				}
				else if (IsValidFilePath(argument))
				{
					FilePaths.Add(argument);
				}
				else if (IsHelpOption(argument))
				{
					HelpAsked = true;
				}
				else
				{
					Console.WriteLine(argument + " is a not a valid option, use -h for help");
				}
			}
		}

		/// <summary>
		/// Convert the precedence argument strings to TagPrecedence
		/// </summary>
		/// <param name="arg">The argument to convert</param>
		/// <param name="worked">Whether the conversion worked</param>
		/// <returns>The value of the argument converted, always ExifXMPExifXMP if the
		/// conversion did not work</returns>
		private TagPrecedence ConvertPrecedenceStrings(string arg, out bool worked)
		{
			worked = false;
			if (!string.IsNullOrEmpty(arg))
			{
				string normalized = arg.ToLower();
				if (normalized.Equals("e-xe-x"))
				{
					worked = true;
					return TagPrecedence.Exif_XMPExif_XMP;
				}
				else if (normalized.Equals("e-x-xe"))
				{
					worked = true;
					return TagPrecedence.Exif_XMP_XMPExif;
				}
				else if (normalized.Equals("xe-e-x"))
				{
					worked = true;
					return TagPrecedence.XMPExif_Exif_XMP;
				}
				else if (normalized.Equals("xe-x-e"))
				{
					worked = true;
					return TagPrecedence.XMPExif_XMP_Exif;
				}
				else if (normalized.Equals("x-e-xe"))
				{
					worked = true;
					return TagPrecedence.XMP_Exif_XMPExif;
				}
				else if (normalized.Equals("x-xe-e"))
				{
					worked = true;
					return TagPrecedence.XMP_XMPExif_Exif;
				}
			}
			return TagPrecedence.Exif_XMPExif_XMP;
		}

		/// <summary>
		/// Convert the true and false argument strings to bools
		/// </summary>
		/// <param name="arg">The argument to convert</param>
		/// <param name="worked">Whether the conversion worked</param>
		/// <returns>The value of the argument converted, always true if the
		/// conversion did not work</returns>
		private bool ConvertTrueFalseStrings(string arg, out bool worked)
		{
			worked = false;
			if (!string.IsNullOrEmpty(arg))
			{
				string normalized = arg.ToLower();
				if (normalized.Equals("t") || normalized.Equals("true"))
				{
					worked = true;
					return true;
				}
				else if (normalized.Equals("f") || normalized.Equals("false"))
				{
					worked = true;
					return false;
				}
			}
			return true;
		}

		/// <summary>
		/// Get whether the argument is the string for the help option
		/// </summary>
		/// <param name="arg">The argument to check</param>
		/// <returns>True if it is, false if not</returns>
		private bool IsHelpOption(string arg)
		{

			if (!string.IsNullOrEmpty(arg))
			{
				string normalized = arg.ToLower();
				if (normalized.Equals("-h") || normalized.Equals("-help"))
				{
					return true;
				}
			}
			return false;
		}

		/// <summary>
		/// Get whether the argument is the string for the load Exif option
		/// </summary>
		/// <param name="arg">The argument to check</param>
		/// <returns>True if it is, false if not</returns>
		private bool IsLoadExifOption(string arg)
		{

			if (!string.IsNullOrEmpty(arg))
			{
				string normalized = arg.ToLower();
				if (normalized.Equals("-e") || normalized.Equals("-exif"))
				{
					return true;
				}
			}
			return false;
		}

		/// <summary>
		/// Get whether the argument is the string for the load XMPExif option
		/// </summary>
		/// <param name="arg">The argument to check</param>
		/// <returns>True if it is, false if not</returns>
		private bool IsLoadXMPExifOption(string arg)
		{

			if (!string.IsNullOrEmpty(arg))
			{
				string normalized = arg.ToLower();
				if (normalized.Equals("-xe") || normalized.Equals("-xmpexif"))
				{
					return true;
				}
			}
			return false;
		}

		/// <summary>
		/// Get whether the argument is the string for the load XMP option
		/// </summary>
		/// <param name="arg">The argument to check</param>
		/// <returns>True if it is, false if not</returns>
		private bool IsLoadXMPOption(string arg)
		{

			if (!string.IsNullOrEmpty(arg))
			{
				string normalized = arg.ToLower();
				if (normalized.Equals("-x") || normalized.Equals("-xmp"))
				{
					return true;
				}
			}
			return false;
		}

		/// <summary>
		/// Get whether the argument is the string for the precedence option
		/// </summary>
		/// <param name="arg">The argument to check</param>
		/// <returns>True if it is, false if not</returns>
		private bool IsPrecedenceOption(string arg)
		{

			if (!string.IsNullOrEmpty(arg))
			{
				string normalized = arg.ToLower();
				if (normalized.Equals("-p") || normalized.Equals("-precedence"))
				{
					return true;
				}
			}
			return false;
		}

		/// <summary>
		/// Get whether the argument is a valid file path
		/// </summary>
		/// <param name="arg">The argument to check</param>
		/// <returns>True if it is, false if not</returns>
		private bool IsValidFilePath(string arg)
		{
			return System.IO.File.Exists(arg);
		}


		/// <summary>
		/// Set the default values
		/// </summary>
		private void SetDefaults()
		{
			LoadExif = true;
			LoadXMPExif = true;
			LoadXMP = true;
			Precedence = TagPrecedence.Exif_XMPExif_XMP;
			FilePaths = new List<string>();
			HelpAsked = false;
		}

		/// <summary>
		/// Get or set the arguments
		/// </summary>
		private string[] Arguments
		{
			get;
			set;
		}

		/// <summary>
		/// Get the collection of file paths to open
		/// </summary>
		public List<string> FilePaths
		{
			get;
			private set;
		}

		/// <summary>
		/// Get whether or not any file paths were passed in the 
		/// application arguments
		/// </summary>
		public bool HasFilePaths
		{
			get
			{
				return FilePaths.Count > 0;
			}
		}

		/// <summary>
		/// Get whether or not to load Exif tags
		/// </summary>
		/// <remarks>
		/// Defaults to true
		/// </remarks>
		public bool LoadExif
		{
			get;
			private set;
		}

		/// <summary>
		/// Get whether or not to load XMP Exif tags
		/// </summary>
		/// <remarks>
		/// Defaults to true
		/// </remarks>
		public bool LoadXMPExif
		{
			get;
			private set;
		}

		/// <summary>
		/// Get whether or not to load XMP tags
		/// </summary>
		/// <remarks>
		/// Defaults to true
		/// </remarks>
		public bool LoadXMP
		{
			get;
			private set;
		}

		/// <summary>
		/// Get the tag precedence
		/// </summary>
		/// <remarks>
		/// Defaults to Exif > XMPExif > XMP
		/// </remarks>
		public TagPrecedence Precedence
		{
			get;
			private set;
		}

		/// <summary>
		/// Get whether or not help was asked in the arguments
		/// </summary>
		public bool HelpAsked
		{
			get;
			private set;
		}

		/// <summary>
		/// Get the help string
		/// </summary>
		public string HelpString
		{
			get
			{
				string help = "Tag Printer options: \n";
				help += "-e Whether to load Exif tags, followed by 't' or 'f'. Defaults to true.\n";
				help += "-xe Whether to load XMPExif tags, followed by 't' or 'f'. Defaults to true. \n";
				help += "-x Whether to load XMP tags, followed by 't' or 'f'. Defaults to true. \n";
				help += "FILE PATH A file path to an image to read. For example \"C:\\Users\\User\\Desktop\\image.png\" \n";
				help += "-p The tag precedence, used in resolving conflicts between common tags in the different tag systems. Possible values include: \n";
				help += "   e-xe-x   Exif > XMPExif > XMP \n";
				help +=	"   e-x-xe   Exif > XMP > XMPExif \n";
				help += "   xe-e-x   XMPExif > Exif > XMP \n";
				help += "   xe-x-e   XMPExif > XMP > Exif \n";
				help += "   x-e-xe   XMP > Exif > XMPExif \n";
				help += "   x-xe-e   XMP > XMPExif > Exif \n";
				help += "   Defaults to Exif > XMPExif > XMP \n";
				help += "-h Help \n";
				help += "Order or arugments does not matter. \n";
				help += "There can as a many file path arguments as you want, but there must be at least one.";
				return help;
			}
		}
	}
}
